# Python面向对象进阶 - 封装和私有属性

"""
封装是面向对象编程的三大特性之一（另外两个是继承和多态）
封装的主要作用：
1. 保护数据安全 - 防止数据被随意修改
2. 隐藏实现细节 - 只暴露必要的接口给外部使用
3. 提高代码可维护性 - 内部实现的修改不会影响外部调用
"""


class BankAccount:
    """银行账户类 - 用于演示封装和私有属性/方法的使用"""

    def __init__(self, account_holder, initial_balance=0):
        # 使用双下划线前缀定义私有属性
        self.__holder = account_holder  # 私有属性：账户持有人
        self.__balance = initial_balance  # 私有属性：账户余额
        self.__transaction_history = []  # 私有属性：交易历史

    def get_balance(self):
        """公共方法：查询余额"""
        return self.__balance

    def get_holder(self):
        """公共方法：获取账户持有人姓名"""
        return self.__holder

    def deposit(self, amount):
        """公共方法：存款"""
        if amount > 0:
            self.__balance += amount
            self.__record_transaction("存款", amount)
            return True
        return False

    def withdraw(self, amount):
        """公共方法：取款"""
        if 0 < amount <= self.__balance:
            self.__balance -= amount
            self.__record_transaction("取款", amount)
            return True
        return False

    def __record_transaction(self, transaction_type, amount):
        """私有方法：记录交易
        使用双下划线前缀定义私有方法，只能在类内部使用
        """
        transaction = f"{transaction_type}: {amount}元"
        self.__transaction_history.append(transaction)

    def get_transaction_history(self):
        """公共方法：获取交易历史"""
        return self.__transaction_history.copy()  # 返回副本防止外部修改


# 测试代码
if __name__ == "__main__":
    # 创建银行账户
    account = BankAccount("张三", 1000)

    # 测试公共方法
    print(f"账户持有人: {account.get_holder()}")
    print(f"初始余额: {account.get_balance()}元")

    # 进行一些交易
    account.deposit(500)
    account.withdraw(200)

    # 尝试直接访问私有方法（会失败）
    try:
        account.__record_transaction("测试", 100)  # 这将引发AttributeError
    except AttributeError as e:
        print("\n无法直接访问私有方法：", e)

    # 查看交易历史
    print("\n交易记录:")
    for transaction in account.get_transaction_history():
        print(transaction)

    # 尝试直接访问私有属性（会失败）
    try:
        print(account.__balance)  # 这将引发AttributeError
    except AttributeError as e:
        print("\n无法直接访问私有属性：", e)

    # 说明：Python的私有属性其实是通过名称改写实现的
    # 类的私有属性实际上被改写为：_类名__属性名
    # 虽然理论上仍可以访问，但这违背了封装的原则，不应这样做
    print(f"\n当前余额: {account.get_balance()}元")
